package edu.hubu.talentmanagementsystem.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.base.CaseFormat;
import edu.hubu.talentmanagementsystem.common.QnUploadUtils;
import edu.hubu.talentmanagementsystem.common.RoleType;
import edu.hubu.talentmanagementsystem.mapper.CompanyMapper;
import edu.hubu.talentmanagementsystem.mapper.PermissionMapper;
import edu.hubu.talentmanagementsystem.mapper.context.MapperContext;
import edu.hubu.talentmanagementsystem.model.ext.Company;
import edu.hubu.talentmanagementsystem.model.ext.Role;
import edu.hubu.talentmanagementsystem.model.ext.RolePermission;
import edu.hubu.talentmanagementsystem.service.ICompanyService;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import edu.hubu.talentmanagementsystem.common.EncodeOperation;
import edu.hubu.talentmanagementsystem.common.EncodeParam;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author moonlan
 * date 2021/3/2 下午8:45
 */
@SuppressWarnings(value = "unused")
@Service
@Transactional(rollbackFor = Exception.class)
public class CompanyServiceImpl extends ServiceImpl<CompanyMapper, Company> implements ICompanyService {

    private final MapperContext context;
    private final BCryptPasswordEncoder encoder;
    private final QnUploadUtils qnUploadUtils;

    public CompanyServiceImpl(MapperContext context, BCryptPasswordEncoder encoder, QnUploadUtils qnUploadUtils) {
        this.context = context;
        this.encoder = encoder;
        this.qnUploadUtils = qnUploadUtils;
    }

    @Override
    public boolean deleteById(Integer id) {
        return context.getCompanyMapper().deleteById(id) > 0;
    }

    @Override
    @EncodeOperation
    public Optional<Company> insert(@EncodeParam Company record) {
        int insert = context.getCompanyMapper().insert(record);
        if (insert > 0) {
            return Optional.of(context.getCompanyMapper().selectById(record.primaryKeyValue()));
        }
        return Optional.empty();
    }

    @Override
    public Optional<Company> selectById(Integer id) {
        QueryWrapper<Company> wrapper = new QueryWrapper<>();
        LambdaQueryWrapper<Company> lambdaQueryWrapper = getColumnWrapper(wrapper.lambda()).eq(Company::getCompanyId,
                id);
        return Optional.of(context.getCompanyMapper().selectOne(lambdaQueryWrapper));
    }

    @Override
    public List<Company> selectAll(String order) {
        QueryWrapper<Company> wrapper = new QueryWrapper<>();
        if (!StringUtils.hasText(order)) {
            LambdaQueryWrapper<Company> select = getColumnWrapper(wrapper.lambda());
            return context.getCompanyMapper().selectList(select);
        }
        wrapper.orderByAsc(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, order));
        LambdaQueryWrapper<Company> select = getColumnWrapper(wrapper.lambda());
        return context.getCompanyMapper().selectList(select);
    }

    @Override
    public Page<Company> selectAllPaged(Integer currentPage,
                                        Integer pageSize, String order) {
        QueryWrapper<Company> wrapper = new QueryWrapper<>();
        Page<Company> page = new Page<>(currentPage, pageSize);
        if (!StringUtils.hasText(order)) {
            LambdaQueryWrapper<Company> select = getColumnWrapper(wrapper.lambda());
            return context.getCompanyMapper().selectPage(page, select);
        }
        wrapper.orderByAsc(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, order));
        LambdaQueryWrapper<Company> select = getColumnWrapper(wrapper.lambda());
        return context.getCompanyMapper().selectPage(page, select);
    }

    private LambdaQueryWrapper<Company> getColumnWrapper(LambdaQueryWrapper<Company> wrapper) {
        return wrapper.select(
                Company::getResource
                ,
                Company::getRole
                ,
                Company::getCompanyLogoId
                ,
                Company::getCompanyRoleId
                ,
                Company::getCompanyId
                ,
                Company::getCompanyNum
                ,
                Company::getCompanyName
                ,
                Company::getCompanyAddress
                ,
                Company::getCompanyPhoneNumber
                ,
                Company::getCompanyEmail
                ,
                Company::getCompanyScale
                ,
                Company::getCompanyDesc
                ,
                Company::getCompanyIsEnable
        );
    }

    @Override
    public Page<Company> selectLikePaged(Integer currentPage,
                                         Integer pageSize, Company record, String order) {
        Page<Company> page = new Page<>(currentPage, pageSize);
        QueryWrapper<Company> wrapper = new QueryWrapper<>();
        if (!StringUtils.hasText(order)) {
            return context.getCompanyMapper().selectPage(page, getColumnWrapper(getQueryWrapper(wrapper, record)));
        }
        wrapper.orderByAsc(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, order));
        return context.getCompanyMapper().selectPage(page, getColumnWrapper(getQueryWrapper(wrapper, record)));
    }

    private LambdaQueryWrapper<Company> getQueryWrapper(QueryWrapper<Company> wrapper, Company record) {
        LambdaQueryWrapper<Company> lambda = wrapper.lambda();
        if (record.getResource() != null) {
            lambda = lambda.eq(Company::getResource, record.getResource());
        }
        if (record.getRole() != null) {
            lambda = lambda.eq(Company::getRole, record.getRole());
        }
        if (record.getCompanyLogoId() != null) {
            lambda = lambda.eq(Company::getCompanyLogoId, record.getCompanyLogoId());
        }
        if (record.getCompanyRoleId() != null) {
            lambda = lambda.eq(Company::getCompanyRoleId, record.getCompanyRoleId());
        }
        if (record.getCompanyId() != null) {
            lambda = lambda.eq(Company::getCompanyId, record.getCompanyId());
        }
        if (record.getCompanyScale() != null) {
            lambda = lambda.eq(Company::getCompanyScale, record.getCompanyScale());
        }
        if (record.getCompanyIsEnable() != null) {
            lambda = lambda.eq(Company::getCompanyIsEnable, record.getCompanyIsEnable());
        }
        if (record.getCompanyNum() != null) {
            lambda = lambda.like(Company::getCompanyNum, record.getCompanyNum());
        }
        if (record.getCompanyAdminPwd() != null) {
            lambda = lambda.like(Company::getCompanyAdminPwd, record.getCompanyAdminPwd());
        }
        if (record.getCompanyName() != null) {
            lambda = lambda.like(Company::getCompanyName, record.getCompanyName());
        }
        if (record.getCompanyAddress() != null) {
            lambda = lambda.like(Company::getCompanyAddress, record.getCompanyAddress());
        }
        if (record.getCompanyPhoneNumber() != null) {
            lambda = lambda.like(Company::getCompanyPhoneNumber, record.getCompanyPhoneNumber());
        }
        if (record.getCompanyEmail() != null) {
            lambda = lambda.like(Company::getCompanyEmail, record.getCompanyEmail());
        }
        if (record.getCompanyDesc() != null) {
            lambda = lambda.like(Company::getCompanyDesc, record.getCompanyDesc());
        }
        return lambda;
    }

    public int count(Company record) {
        return context.getCompanyMapper().selectCount(getQueryWrapper(new QueryWrapper<>(), record));
    }

    @Override
    @EncodeOperation
    public Optional<Company> updateById(Integer id, @EncodeParam Company record) {
        record.setCompanyId(id);
        int update = context.getCompanyMapper().updateById(record);
        if (update > 0) {
            QueryWrapper<Company> wrapper = new QueryWrapper<>();
            LambdaQueryWrapper<Company> lambdaQueryWrapper =
                    getColumnWrapper(wrapper.lambda()).eq(Company::getCompanyId, id);
            return Optional.of(context.getCompanyMapper().selectOne(getColumnWrapper(lambdaQueryWrapper)));
        }

        return Optional.empty();
    }

    @Override
    public Optional<Company> selectByNum(String num) {
        LambdaQueryWrapper<Company> wrapper = new QueryWrapper<Company>().lambda();
        Company company = context.getCompanyMapper().selectOne(wrapper.eq(Company::getCompanyNum, num));
        Role role = context.getRoleMapper().selectById(company.getCompanyRoleId());
        LambdaQueryWrapper<RolePermission> rolePermissionLambdaQueryWrapper =
                new QueryWrapper<RolePermission>().lambda().eq(RolePermission::getRolePermissionRoleId,
                        role.getRoleId());
        List<RolePermission> rolePermissions =
                context.getRolePermissionMapper().selectList(rolePermissionLambdaQueryWrapper);
        role.setPermissions(rolePermissions.stream().map(rolePermission -> {
            PermissionMapper permissionMapper = context.getPermissionMapper();
            return permissionMapper.selectById(rolePermission.getRolePermissionPermissionId());
        }).collect(Collectors.toList()));
        company.setRole(role);
        return Optional.of(company);
    }

    public boolean updatePwd(Integer id, String curPwd, String updatePwd) {
        Company company = context.getCompanyMapper().selectById(id);
        if (!encoder.matches(curPwd, company.getCompanyAdminPwd())) {
            throw new BadCredentialsException("认证失败");
        }

        company.setCompanyAdminPwd(encoder.encode(updatePwd));
        return context.getCompanyMapper().updateById(company) > 0;
    }

    @Override
    public List<Company> selectStaffFollowCompanies(Integer staffId) {
        List<Company> companies = context.getCompanyMapper().selectStaffFollowCompanies(staffId);
        for (Company company : companies) {
            company.getResource().setResourceUrl(qnUploadUtils.getPrivateUrl(company.getResource().getResourceUrl()));
        }
        return companies;
    }

    @Override
    public boolean register(Company company) {
        company.setCompanyAdminPwd(encoder.encode(company.getCompanyAdminPwd()));
        company.setCompanyRoleId(context.getRoleMapper()
                .selectOne(new QueryWrapper<Role>().eq("role_name",RoleType.COMPANY.name())).getRoleId());
        return context.getCompanyMapper().insert(company) > 0;
    }
}
